Daily Notes

Just Some Notes

  • 选择排序

    /**
     * 选择排序,时间复杂度为O(N^2)
     */
    function selectSort(arr) {
        for (let i = 0; i < arr.length - 1; i++) {
            let idxOfMinVal = i, curVal = arr[i];
            for (let j = i + 1; j < arr.length; j++) {
                if (arr[j] < curVal) {
                    curVal = arr[j];
                    idxOfMinVal = j;
                }
            }
            if (idxOfMinVal != i) {
                [arr[i], arr[idxOfMinVal]] = [arr[idxOfMinVal], arr[i]];
            }
        }
    }
    
    // test
    const arr = new Array(10);
    for (let i = 0; i < arr.length; i++) {
        arr[i] = Math.round(Math.random() * 90 + 10)
    }
    console.log(arr);
    selectSort(arr);
    console.log(arr);
    
    阅读全文
  • 冒泡排序

    /**
     * 冒泡排序,时间复杂度为O(N^2)
     */
    function bubbleSort(arr) {
        for (i = arr.length - 1; i > 0; i--) {
            for (j = 0; j < i; j++) {
                if (arr[j] > arr[j + 1]) {
                    [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
                }
            }
        }
    }
    // test
    const arr = new Array(10);
    for (let i = 0; i < arr.length; i++) {
        arr[i] = Math.round(Math.random() * 80 + 20)
    }
    console.log(arr);
    bubbleSort(arr);
    console.log(arr);
    
    阅读全文
  • 计算斐波拉契数列

    纯粹的递归版

    /**
     * 单纯的进行递归操作效率及其低下,因为算法内部做了大量的重复计算,时间复杂度为O(2^n)
     */
    function fibonacci(n) {
        if (n <= 1) {
            return n;
        } else {
            return fibonacci(n - 1) + fibonacci(n - 2);
        }
    }
    

    带缓存的递归版

    /**
     * 将计算好的结果缓存起来,这样可以避免重复计算,时间复杂度为O(n)
     */
    const memory = [0, 1];
    function fibonacci(n) {
        if (typeof memory[n] === 'number') {
            return memory[n];
        } else {
            const result = fibonacci(n - 1) + fibonacci(n - 2);
            memory[n] = result;
            return result;
        }
    }
    

    循环版

    阅读全文
  • 实现函数节流

    /**
     * 函数节流
     * @param {function} func 需要节流的函数
     * @param {number} interval 函数的执行间隔(毫秒)
     * @param {object} options { leading: true, tailing: false }
     */
    function throttle(func, interval, options) {
        let canRun = false,    // 是否可以执行函数
            lastInvokeTime = 0,    // 函数上一次被执行的时刻(时间戳)
            tid = null;    // 定时器id,设置间隔过后再次执行一次函数
        // leading和tailing不能同时为false
        const { leading = true, tailing = false } = options || {};
        const throttled = function throttled(...args) {
            let now = Date.now();
            if (!lastInvokeTime) {
                if (leading) {
                    canRun = true;
                }
            } else {
                if (now - lastInvokeTime >= interval) {
                    canRun = true;
                }
            }
            if (canRun) {
                if (tid) {
                    clearTimeout(tid);
                    tid = null;
                }
                canRun = false;
                lastInvokeTime = now;
                func.apply(this, args);
            } else if (!tid && tailing) {
                tid = setTimeout(function () {
                    func.apply(this, args);
                    lastInvokeTime = 0;
                    tid = null;
                }, now - lastInvokeTime);
            }
        }
    
        /**
         * 取消最后一次的函数执行
         */
        throttled.cancel = function cancel() {
            lastInvokeTime = 0;
            if (tid) {
                clearTimeout(tid);
                tid = null;
            }
        }
    
        return throttled;
    }
    
    // test
    let count = 0;
    function increment() {
        count += 1;
        console.log((new Date().getSeconds()), count);
    }
    
    const incrementThrottled = throttle(increment, 3000);
    
    while (count < 5) {
        incrementThrottled();
    }
    // test result
    // 47 1
    // 50 2
    // 53 3
    // 56 4
    // 59 5
    
    
    阅读全文
  • 利用reduce方法实现map方法

    /**
     * 利用reduce方法实现map方法
     * @param {function} callback map回调函数
     * @param {object} context callback执行时的this上下文对象
     */
    Array.prototype.mapImplementedByReduce = function (callback, context = null) {
        const reducer = function (accumulator, currentValue, index, array) {
            const result = callback.call(context, currentValue, index, array);
            accumulator.push(result);
            return accumulator;
        }
        return this.reduce(reducer, []);
    }
    
    /**
     * test
     */
    const arr = [1, 3, 5];
    const callback = function (number, index, array) {
        return Math.pow(number, 3);
    }
    
    console.log(arr.mapImplementedByReduce(callback)); // [ 1, 27, 125 ]
    
    阅读全文
  • redux源代码阅读

    Redux是一个常用的组件状态管理库,通过将应用的状态数据集中存储并且限制可以更改状态数据的路径,使得开发者可以更好的追踪以及预测应用状态的变化过程,Redux的源代码不到1000行,是一个学习源代码分析的不错对象.

    在浏览器中通过script标签加载后,脚本会在全局作用域下添加Redux变量.
    redux object screenshot

    对应的源代码如下

    /**
     * 先探测脚本所处的运行环境和加载机制,然后将redux的方法和属性挂载到对应的作用域
     * 1. Node.js环境下和AMD加载机制下挂载到模块的导出对象
     * 2. script标签加载挂载到window对象
     */
    (function (global, factory) {
        // Node.js环境
        typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
            // 浏览器环境(通过AMD方式加载)
            typeof define === 'function' && define.amd ? define(['exports'], factory) :
                // 浏览器环境(通过script标签加载)
                (global = global || self, factory(global.Redux = {}));
    }(this, function (exports) {
    
        /* other code... */
    
        exports.__DO_NOT_USE__ActionTypes = ActionTypes;
        exports.applyMiddleware = applyMiddleware;
        exports.bindActionCreators = bindActionCreators;
        exports.combineReducers = combineReducers;
        exports.compose = compose;
        exports.createStore = createStore;
    
        Object.defineProperty(exports, '__esModule', { value: true });
    }));
    

    __DO_NOT_USE__ActionTypes

    阅读全文
  • HTTP缓存策略

    一般来说,对于html, css, js以及图片等静态资源文件,浏览器会进行缓存,这样下次访问这些资源的时候就可以直接从缓存获取,从而提升页面的加载速度,但是浏览器的缓存机制遵循一定的策略.

    什么情况下会缓存?

    如果希望资源被浏览器缓存到本地,需要满足以下条件:

    1. http响应头Content-type必须标明当前资源是可被缓存的静态资源,例如text/html, application/javascript, text/css, image/png等等
    2. http响应头Cache-Control指明了该资源允许被缓存

    与缓存有关的HTTP请求头和响应头?

    阅读全文
  • 前端优化路径图

    微博上看到的关于前端优化的图
    前端优化图

    阅读全文
  • js中的in操作符和Object.keys方法

    in操作符

    intypeof一样,只是操作符,不是函数,它用来判断对象是否拥有某个属性,例如:

    console.log('alert' in window); // true
    console.log('xxoo' in window); // false
    

    在js中,对象的属性查找和继承是基于原型链来实现的,可以使用hasOwnProperty方法判断一个属性是属于对象本身,还是属于它的上层原型:

    console.log(window.hasOwnProperty('alert')); // true
    console.log(([]).hasOwnProperty('slice')); // false
    
    阅读全文
  • 洗牌算法

    洗牌算法,用于随机打乱一个有限列表内的元素顺序,目前公认最好的洗牌算法就是Fisher-Yates算法,使用JavaScript实现Fisher-Yates算法对一个数组进行顺序打乱的代码如下.

    /**
     * Fisher-Yates算法
     * 将数组元素的顺序原地打乱
     * 时间复杂度O(N)
     * @param {Array<any>} 数组
     */
    function shuffle(arr) {
        for (let i = arr.length - 1; i > 0; i--) {
            const idx = Math.floor(Math.random() * (i + 1));
            const tmp = arr[i];
            arr[i] = arr[idx];
            arr[idx] = tmp; 
        }
    }
    
    阅读全文